﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Studio.Custom;
using DWF.Studio.Host;
using DWF.Studio.Models;
using DWF.Studio.Models.Enum;
using DWF.Studio.RemoteCtrls;
using DWF.Studio.Script.Excutor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DWF.Studio.Script.Implementation
{
    /// <summary>
    /// 工作流脚本 表示一个编辑中脚本
    /// </summary>
    internal class WorkflowScript : ScriptBase
    {
        private RemoteDesignerHost _designerHost = null;

        protected RemoteDesignerHost CurrentDesignerHost
        {
            get
            {
                return _designerHost;
            }

            set
            {
                _designerHost = value;
            }
        }

        protected WorkflowScript()
        {
        }

        public WorkflowScript(string projectDirectory, string path, bool isStart = false)
        {
            this.IsStart = isStart;
            this.ProjectDirectory = projectDirectory;
            this.FilePath = path;
            this.FileName = Path.GetFileName(this.FilePath);
            var loaderHost = RemoteLoaderHost.GetCurrentInstance();
            _designerHost = new RemoteDesignerHost(loaderHost.LoadDesignerProxy());
            this.ScriptEditor = _designerHost.GetDesignerView();
            this.PropertyBar1 = _designerHost.GetPropertiesView();
            this.PropertyBar2 = _designerHost.GetOutlineView();

            _designerHost.DesignModelChanged = (e) =>
            {
                this.IsEditorContentChanged = true;
                EditorContentChanged?.Invoke(EventArgs.Empty);
                Task.Run(() =>
                {
                    Thread.Sleep(2000);
                    GlobalActionHandler.BreakPointFresh?.Invoke(EventArgs.Empty);
                });
            };

            this._designerHost.BreakpointChanged = (e) =>
            {
                this.BreakPointChanged?.Invoke(new BreakpointEventArgs(new Breakpoint()
                {
                    Path = this.FilePath,
                    ActivityId = e.Breakpoint.ActivityId,
                    ActivityType = e.Breakpoint.ActivityType,
                    ActivityName = e.Breakpoint.ActivityName,
                    BreakpointType = (int)e.Breakpoint.BreakpointType,
                    RefId = e.Breakpoint.RefId

                }, e.Operation.WFToOperation()));
            };
            this._designerHost.PropertyModelChanged = (e) =>
            {
                GlobalActionHandler.LoadPutParam?.Invoke(e);
            };
        }

        /// <summary>
        /// 重新加载
        /// </summary>
        /// <param name="scriptExcutor"></param>
        public void Reload(IEnumerable<Breakpoint> breakpoints)
        {
            var loaderHost = RemoteLoaderHost.GetCurrentInstance();
            _designerHost = new RemoteDesignerHost(loaderHost.LoadDesignerProxy());

            this.ScriptEditor = _designerHost.GetDesignerView();
            this.PropertyBar1 = _designerHost.GetPropertiesView();
            this.PropertyBar2 = _designerHost.GetOutlineView();

            _designerHost.DesignModelChanged = (e) =>
            {
                this.IsEditorContentChanged = true;
                EditorContentChanged?.Invoke(EventArgs.Empty);
            };

            this._designerHost.BreakpointChanged = (e) =>
            {
                this.BreakPointChanged?.Invoke(new BreakpointEventArgs(new Breakpoint()
                {
                    Path = this.FilePath,
                    ActivityId = e.Breakpoint.ActivityId,
                    ActivityType = e.Breakpoint.ActivityType,
                    ActivityName = e.Breakpoint.ActivityName,
                    BreakpointType = (int)e.Breakpoint.BreakpointType,
                    RefId = e.Breakpoint.RefId

                }, e.Operation.WFToOperation()));
            };

            var bps = breakpoints.Select(item => new BreakpointInfo(item.ActivityId, item.ActivityName, item.ActivityType, (EBreakpointType)item.BreakpointType, item.RefId)).ToList();
            _designerHost.Load(this.FilePath, bps);
        }

        /// <summary>
        /// 释放
        /// </summary>
        public override void Dispose()
        {
            DisposeView();
        }

        /// <summary>
        /// 释放视图
        /// </summary>
        public void DisposeView()
        {
            this.ScriptEditor = null;
            this.PropertyBar1 = null;
            this.PropertyBar2 = null;
            this._designerHost?.Dispose();
            this._designerHost = null;
        }

        /// <summary>
        /// 加载
        /// </summary>
        public override void Load()
        {
            if (_designerHost != null)
            {
                _designerHost.Load(this.FilePath);
            }
        }

        public override void Load(IEnumerable<Breakpoint> breakpoints)
        {
            if (_designerHost != null)
            {
                var bps = breakpoints?.Select(item => new BreakpointInfo(item.ActivityId, item.ActivityName, item.ActivityType, (EBreakpointType)item.BreakpointType, item.RefId)).ToList();
                _designerHost.Load(this.FilePath, bps);
            }
        }

        /// <summary>
        /// 保存
        /// </summary>
        public override void Save()
        {
            this.IsEditorContentChanged = false;
            if (_designerHost != null)
            {
                _designerHost.Save(this.FilePath);
            }
        }

        public override bool TrySave(out string messge)
        {
            var result = false;
            messge = String.Empty;
            var infos = _designerHost.Validate();
            var exceptionInfo = infos.FirstOrDefault(item => item.IsException);
            if (exceptionInfo != null)
            {
                messge = exceptionInfo.Message;
            }
            else
            {
                Save();
                result = true;
            }

            return result;
        }

        /// <summary>
        /// 添加活动到Sequence
        /// </summary>
        /// <param name="parentDisplayName">父活动的显示名称</param>
        /// <param name="activityTypeName">活动类型</param>
        /// <param name="param">参数</param>
        public string AddActivityByParentCode(string parentCode, string activityTypeName, IDictionary<string, object> param)
        {
            return _designerHost?.AddActivityByParentCode(parentCode, activityTypeName, param);
        }

        public string GetRootActivityTypeName()
        {
            return _designerHost?.GetRootActivityTypeName();
        }

        public string GetRootActivityCode()
        {
            return _designerHost?.GetRootActivityCode();
        }

        public void SetActivityByCode(string activityCode, IDictionary<string, object> param)
        {
            _designerHost?.SetActivityByCode(activityCode, param);
        }

        public void SelectActivityById(string activityId)
        {
            _designerHost?.SelectActivityById(activityId);
        }
        public void ActivitySelectionById(string activityId)
        {
            _designerHost?.ActivitySelectionById(activityId);
        }

        public void FocusActivityByIdRef(string activityIdRef)
        {
            _designerHost.SelectActivityByIdRef(activityIdRef);
        }
        public void SetChangeArgument(List<ProjectParam> projectParams)
        {
            _designerHost.SetChangeArgument(projectParams);
        }

        public void SetInArgument(ProjectParam projectParam)
        {
            _designerHost.SetInArgument(projectParam);
        }
        public void SetOutArgument(ProjectParam projectParam)
        {
            _designerHost.SetOutArgument(projectParam);
        }
        public override void Cut()
        {
            _designerHost?.InvokeCutCommand();
        }

        public override void Copy()
        {
            _designerHost?.InvokeCopyCommand();
        }

        public override void Paste()
        {
            _designerHost?.InvokePasteCommand();
        }

        public override void Undo()
        {
            _designerHost?.InvokeUndoCommand();
        }

        public override void Redo()
        {
            _designerHost?.InvokeRedoCommand();
        }

        public override void ToggleBreakPoint()
        {
            _designerHost?.ToggleBreakPoint();
        }

        public override void EnableBreakPoint(IEnumerable<Breakpoint> breakpoints)
        {
            _designerHost?.EnableBreakPoint(breakpoints);
        }
        public override void BoundedBreakPoint(IEnumerable<Breakpoint> breakpoints)
        {
            _designerHost?.BoundedBreakPoint(breakpoints);
        }

        public override void DeleteBreakPoint(Breakpoint breakpoint)
        {
            _designerHost?.DeleteBreakPoint(breakpoint);
        }
        public override void DeleteAllBreakPoints(IEnumerable<Breakpoint> breakpoints)
        {
            _designerHost?.DeleteAllBreakPoints();
        }
        public override void SetReadOnly(bool isReadOnly)
        {
            IsReadOnly = isReadOnly;
            _designerHost?.SetReadOnly(isReadOnly);
        }

        public override void DebugStart()
        {
            _designerHost?.DebugStart();
        }

        public override void DebugEnd()
        {
            _designerHost?.DebugEnd();
        }

        public override bool Validate(out string message)
        {
            var result = false;
            var infos = XamlAnalyzerHost.Validate(this.FilePath);
            result = infos.Count() == 0;

            StringBuilder sbuilder = new StringBuilder();
            foreach (var info in infos)
            {
                if (!String.IsNullOrWhiteSpace(info.Id))
                {
                    sbuilder.Append(info.Id);
                    sbuilder.Append(System.Environment.NewLine);
                }

                if (!String.IsNullOrWhiteSpace(info.PropertyName))
                {
                    sbuilder.Append(info.PropertyName);
                    sbuilder.Append(System.Environment.NewLine);
                }

                if (!String.IsNullOrWhiteSpace(info.Message))
                {
                    sbuilder.Append(info.Message);
                    sbuilder.Append(System.Environment.NewLine);
                }
            }
            message = sbuilder.ToString();

            return result;
        }

        public override bool Debug(string location)
        {
            return CurrentDesignerHost.Debug(location);
        }

        public override bool DebugByStep(string location)
        {
            return CurrentDesignerHost.DebugByStep(location);
        }

        public override void Find()
        {
        }

        public override void Replace()
        {
        }
        /// <summary>
        /// 注释
        /// </summary>
        public override void Notes()
        {
            _designerHost?.Notes();
        }
        public override void CancelNotes()
        {
            _designerHost?.CancelNotes();
        }

        public override IEnumerable<Breakpoint> GetBreakpoints()
        {
            return _designerHost?.GetBreakpoints().Select(item =>
                   new Breakpoint
                   {
                       Path = this.FilePath,
                       ActivityId = item.ActivityId,
                       ActivityType = item.ActivityType,
                       ActivityName = item.ActivityName,
                       BreakpointType = (int)item.BreakpointType,
                       RefId = item.RefId
                   });
        }

        public override void ClearCurrentLocation()
        {
            _designerHost?.ClearCurrentLocation();
        }
    }
}
